<template>
  <div>
    <h2>组合式 API 高级特性</h2>
    <br />
    <h3>一、defineExpose</h3>
    <div>用于子组件显式暴露组件实例的属性和方法给父组件</div>
    <div class="define-expose">
      <Counter ref="counterRef" />

      <div class="actions">
        <button @click="callIncrement">调用子组件增加方法</button>
        <button @click="callReset">重置计数器</button>
        <button @click="getCurrentCount">获取当前计数</button>
      </div>

      <p>从父组件获取的计数: {{ parentCount }}</p>
    </div>
    <br />
    <h3>二、getCurrentInstance</h3>
    <div>用于获取当前组件实例</div>
    <br />
    <h3>三、withDefaults</h3>
    <div>用于为 TypeScript 的 defineProps 提供默认值</div>
    <br />

    <h3>五、nextTick</h3>
    <div>event loop</div>
    <br />
    <h3>六、defineOptions()</h3>
    <div>
      仅在 3.3+ 中支持，这个宏可以用来直接在 script setup中声明组件选项，而不必使用单独的 script 块
    </div>
  </div>
</template>

<script setup lang="ts">
import { getCurrentInstance, ref, useAttrs, useSlots } from 'vue'
import Counter from '@/components/DefineExposeCount.vue'

// 仅在 3.3+ 中支持，这个宏可以用来直接在 <script setup> 中声明组件选项，而不必使用单独的 <script> 块
defineOptions({
  inheritAttrs: false,
  customOptions: {
    /* ... */
  },
})

const counterRef = ref<InstanceType<typeof Counter>>()
const parentCount = ref(0)
const callIncrement = () => {
  if (counterRef.value) {
    counterRef.value.increment()
  }
}
const callReset = () => {
  if (counterRef.value) {
    counterRef.value.reset()
  }
}
const getCurrentCount = () => {
  if (counterRef.value) {
    parentCount.value = counterRef.value.getCount()
  }
}

/**
 * getCurrentInstance应用场景：
 * 1. 在组合式 API 中访问组件实例的属性和方法，如$options、parent等
 * 2. 访问通过 app.config.globalProperties挂载的全局对象
 * 3. 访问未被暴露的 API​, 如atts、slots等。attrs、 slots建议用useAttrs、useSlots替代
 * 4. 开发调试
 *
 * 重点：尽量少用
 */
const instance = getCurrentInstance()
console.log(instance?.parent) // 父组件实例
console.log(instance?.vnode) // 虚拟节点信息
console.log(instance?.proxy?.$appName) // 全局属性
console.log(instance?.attrs)
console.log(instance?.slots) // 插槽信息

const attrs = useAttrs()
console.log('useAttrs:', attrs)
console.log('useSlots:', useSlots())
</script>

<style lang="scss" scoped>
.define-expose {
  padding: 1rem;
  border: 1px solid #ddd;
  border-radius: 8px;
  .actions {
    margin-top: 1rem;
  }

  .actions button {
    margin: 0 0.5rem;
    padding: 8px 16px;
    border: none;
    border-radius: 4px;
    background: #28a745;
    color: white;
    cursor: pointer;
  }

  .actions button:hover {
    background: #1e7e34;
  }
}
</style>
